package cc.icourt.kit;

import android.Manifest;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.recyclerview.widget.RecyclerView;

import com.blankj.utilcode.util.GsonUtils;
import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechEvent;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.SpeechSynthesizer;
import com.iflytek.cloud.SynthesizerListener;
import com.iflytek.cloud.VoiceWakeuper;
import com.iflytek.cloud.WakeuperListener;
import com.iflytek.cloud.WakeuperResult;
import com.iflytek.cloud.util.ResourceUtil;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import cc.icourt.kit.adapter.MainAdapter;
import cc.icourt.kit.api.MainService;
import cc.icourt.kit.domain.MainGPT_Data;
import cc.icourt.kit.domain.MainItem;
import cc.icourt.kit.domain.MainRequestBody;
import cc.icourt.kit.typerwriter.TypeWriterTextView;
import cc.icourt.kit.typerwriter.WriteStatusListener;
import cc.icourt.kit.util.JsonParser;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okio.BufferedSource;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * -----------------------------------------------
 * 作    者：高延荣
 * 电    话：18963580395
 * 创建日期：2024/6/5 14:15
 * 描    述：des:
 * 修订历史：
 * -----------------------------------------------
 */
public class MainActivity extends AppCompatActivity {

    private RecyclerView rv;
    private List<MainItem> data = new ArrayList<>();
    private MainAdapter adapter;

    private LinearLayoutCompat llContent;

    private Retrofit retrofit;
    private MainService mainService;


    private SharedPreferences mSharedPreferences;
    private String TAG = "ivw";

    /**
     * 语音唤醒
     */
    // 语音唤醒对象
    private VoiceWakeuper mIvw;
    // 唤醒结果内容
    private String resultString;

    private int curThresh = 1450;
    private String keep_alive = "1";
    private String ivwNetMode = "0";

    /**
     * 语音听写
     */
    private static String TAG2 = "IatDemo";
    // 语音听写对象
    private SpeechRecognizer mIat;
    // 用HashMap存储听写结果
//    private HashMap<String, String> mIatResults = new LinkedHashMap<>();
    //  用 StringBuffer 存 听写结果
    private StringBuffer sb = new StringBuffer();
    private Toast mToast;
    private String mEngineType = "cloud";
    int ret = 0;// 函数调用返回值


    /**
     * 语音合成
     */
    private static String TAG3 = "TtsDemo";
    // 语音合成对象
    private SpeechSynthesizer mTts;
    // 默认云端发音人
    public static String voicerCloud = "xiaoyu";
    // 引擎类型
    private String mTtsEngineType = SpeechConstant.TYPE_CLOUD;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

//        initRv();
        llContent = findViewById(R.id.llContent);
        initRetrofit();

        mSharedPreferences = getSharedPreferences("Kit", Activity.MODE_PRIVATE);

        /**
         * 正常判断隐私协议，这里不判断了
         *
         * 获取权限和初始化对象放一起，
         */
        mPermissionResult.launch(Manifest.permission.RECORD_AUDIO);
        // 初始化唤醒对象
        mIvw = VoiceWakeuper.createWakeuper(this, null);

        /**
         * 语音听写
         */
        // 使用SpeechRecognizer对象，可根据回调消息自定义界面；
        mIat = SpeechRecognizer.createRecognizer(this, mInitListener);

        /**
         * 语音合成
         */
        // 初始化合成对象
        mTts = SpeechSynthesizer.createSynthesizer(this, mTtsInitListener);

    }

    private void initRetrofit() {
        OkHttpClient client = new OkHttpClient.Builder().readTimeout(30, TimeUnit.SECONDS) // 设置读取超时时间为30秒
                .writeTimeout(30, TimeUnit.SECONDS) // 设置写入超时时间为30秒
                .connectTimeout(30, TimeUnit.SECONDS) // 设置连接超时时间为10秒
                .build();
        retrofit = new Retrofit.Builder()
                .baseUrl("http://82.156.55.127:3300/")
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        mainService = retrofit.create(MainService.class);

    }

    /**
     * 创建流 --- 废弃 流请求
     */
    private void createWebSocket(String content) {
        new Thread(new Runnable() {
            @Override
            public void run() {


                MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
                String json = "{\"messages\": [{\"role\": \"user\", \"content\": \"我被打了怎么办\"}], \"stream\": false, \"id\": \"0193kdo93mdo93\"}";
                RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, json);

                OkHttpClient client = new OkHttpClient();

                Request request = new Request.Builder().url("http://82.156.55.127:3300/v1/chat/completions") // 替换为你的服务器端点
                        .post(body).addHeader("Content-Type", "application/json").addHeader("Authorization", "Bearer sk-alpha-gpt-4-speed").build();

                client.newCall(request).enqueue(new okhttp3.Callback() {
                    @Override
                    public void onFailure(okhttp3.Call call, IOException e) {
                        Log.e(TAG2, "onFailure" + e.getMessage());
                    }

                    @Override
                    public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
                        if (!response.isSuccessful()) {
                            // 处理错误响应
                            Log.e(TAG2, "处理错误响应");
                            return;
                        }
                        // 检查是否为SSE流
                        Log.e(TAG2, response.header("Content-Type"));
                        if ("text/event-stream; charset=utf-8".equalsIgnoreCase(response.header("Content-Type"))) {
                            // SSE流处理
                            Log.e(TAG2, "SSE流处理");
                            handleSseStream(response);
                        } else {
                            // 处理常规JSON响应
                            Log.e(TAG2, "处理常规JSON响应" + response.body().source());
                        }
                    }
                });
            }
        }).start();
    }

    private void handleSseStream(okhttp3.Response response) throws IOException {
        BufferedSource source = response.body().source();
        StringBuffer stringBuffer = new StringBuffer();
        while (!source.exhausted()) {
            String line = source.readUtf8LineStrict();
            if (!line.isEmpty() && line.startsWith("data:")) {
                // 处理接收到的SSE事件
                Log.e(TAG2, line.substring(5));
            }
        }
    }


//    private void initRv() {
//        rv = findViewById(R.id.rv);
//        adapter = new MainAdapter(data);
//        rv.setLayoutManager(new LinearLayoutManager(this));
//        rv.setAdapter(adapter);
//    }

    /**
     * 开启请求
     */
    private void startRequest(String content) {
        Log.e(TAG2, "开启网络请求" + content);
        MainRequestBody mainRequestBody = new MainRequestBody(content);
        Log.e(TAG, "请求体: " + GsonUtils.toJson(mainRequestBody));

        mainService.getGPT(mainRequestBody).enqueue(new Callback<MainGPT_Data>() {
            @Override
            public void onResponse(Call<MainGPT_Data> call, Response<MainGPT_Data> response) {
                Log.e(TAG2, "网络请求成功" + response.isSuccessful());
                if (response.isSuccessful()) {
                    Log.e(TAG2, "网络请求成功" + GsonUtils.toJson(response.body()));

                    MainGPT_Data body = response.body();
                    if (body != null && body.choices != null && body.choices.size() > 0) {
                        MainGPT_Data.Choice choice = body.choices.get(0);
                        if (choice != null && choice.message != null) {
//                            data.add(new MainItem(1, choice.message.content));
//                            adapter.notifyItemChanged(data.size() - 1);
                            addKitText(choice.message.content);
                        }
                    }
                }
                startWake();
            }

            @Override
            public void onFailure(Call<MainGPT_Data> call, Throwable t) {
                Log.e(TAG2, "网络请求失败" + t.getMessage());
                startWake();
            }
        });
    }


    /**
     * 开启唤醒监听
     */
    private void startWake() {
        //非空判断，防止因空指针使程序崩溃
        mIvw = VoiceWakeuper.getWakeuper();
        if (mIvw != null) {
            // 清空参数
            mIvw.setParameter(SpeechConstant.PARAMS, null);
            // 唤醒门限值，根据资源携带的唤醒词个数按照“id:门限;id:门限”的格式传入
            mIvw.setParameter(SpeechConstant.IVW_THRESHOLD, "0:" + curThresh);
            // 设置唤醒模式
            mIvw.setParameter(SpeechConstant.IVW_SST, "wakeup");
            // 设置持续进行唤醒
            mIvw.setParameter(SpeechConstant.KEEP_ALIVE, keep_alive);
            // 设置闭环优化网络模式
            mIvw.setParameter(SpeechConstant.IVW_NET_MODE, ivwNetMode);
            // 设置唤醒资源路径
            mIvw.setParameter(SpeechConstant.IVW_RES_PATH, getResource());
            // 设置唤醒录音保存路径，保存最近一分钟的音频
            mIvw.setParameter(SpeechConstant.IVW_AUDIO_PATH, getExternalFilesDir("msc").getAbsolutePath() + "/ivw.wav");
            mIvw.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
            mIvw.startListening(mWakeuperListener);
        }
    }

    /**
     * 关闭唤醒
     */

    private void stopWake() {
        mIvw.stopListening();
    }


    /**
     * 开始听写
     */
    private void startLat() {
        sb.setLength(0);
        // 清空参数
        mIat.setParameter(SpeechConstant.PARAMS, null);
        String lag = mSharedPreferences.getString("iat_language_preference", "mandarin");
        // 设置引擎
        mIat.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
        // 设置返回结果格式
        mIat.setParameter(SpeechConstant.RESULT_TYPE, "json");

        //mIat.setParameter(MscKeys.REQUEST_AUDIO_URL,"true");

        //	this.mTranslateEnable = mSharedPreferences.getBoolean( this.getString(R.string.pref_key_translate), false );
//        if (mEngineType.equals(SpeechConstant.TYPE_LOCAL)) {
//            // 设置本地识别资源
//            mIat.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());
//        }
        // 在线听写支持多种小语种，若想了解请下载在线听写能力，参看其speechDemo
        if (lag.equals("en_us")) {
            // 设置语言
            mIat.setParameter(SpeechConstant.LANGUAGE, "en_us");
            mIat.setParameter(SpeechConstant.ACCENT, null);

            // 设置语言
            mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
            // 设置语言区域
            mIat.setParameter(SpeechConstant.ACCENT, lag);
        }

        // 设置语音前端点:静音超时时间，即用户多长时间不说话则当做超时处理
        mIat.setParameter(SpeechConstant.VAD_BOS, mSharedPreferences.getString("iat_vadbos_preference", "4000"));

        // 设置语音后端点:后端点静音检测时间，即用户停止说话多长时间内即认为不再输入， 自动停止录音
        mIat.setParameter(SpeechConstant.VAD_EOS, mSharedPreferences.getString("iat_vadeos_preference", "1000"));

        // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
        mIat.setParameter(SpeechConstant.ASR_PTT, mSharedPreferences.getString("iat_punc_preference", "1"));

        // 设置音频保存路径，保存音频格式支持pcm、wav，设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
        mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
        mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, getExternalFilesDir("msc").getAbsolutePath() + "/iat.wav");

        // 不显示听写对话框
        ret = mIat.startListening(mRecognizerListener);
        if (ret != ErrorCode.SUCCESS) {
            showTip("听写失败,错误码：" + ret + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");
        } else {
//            showTip("请说");
        }

    }

    /**
     * 关闭语音听写
     */
    private void stopLat() {
        mIat.stopListening();
    }


    /**
     * 听写监听器。
     */
    private RecognizerListener mRecognizerListener = new RecognizerListener() {

        @Override
        public void onBeginOfSpeech() {
            // 此回调表示：sdk内部录音机已经准备好了，用户可以开始语音输入
//            showTip("开始说话");
        }

        @Override
        public void onError(SpeechError error) {
            // Tips：
            // 错误码：10118(您没有说话)，可能是录音机权限被禁，需要提示用户打开应用的录音权限。
//            showTip(error.getPlainDescription(true));
        }

        @Override
        public void onEndOfSpeech() {
            // 此回调表示：检测到了语音的尾端点，已经进入识别过程，不再接受语音输入
//            showTip("结束说话");
            // 把这个 挪到网络请求之后了
//            startWake();
        }

        @Override
        public void onResult(RecognizerResult results, boolean isLast) {

            String text = JsonParser.parseIatResult(results.getResultString());
            sb.append(text);
            if (isLast) {
                //TODO 最后的结果
//                data.add(new MainItem(0, sb.toString()));
//                adapter.notifyItemChanged(data.size() - 1);
                addUserText(sb.toString());
                addWaitView("请稍后！");
                startRequest(sb.toString());
            }
        }

        @Override
        public void onVolumeChanged(int volume, byte[] data) {
//            showTip("当前正在说话，音量大小：" + volume);
            Log.d(TAG, "返回音频数据：" + data.length);
        }

        @Override
        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
            // 以下代码用于获取与云端的会话id，当业务出错时将会话id提供给技术支持人员，可用于查询会话日志，定位出错原因
            // 若使用本地能力，会话id为null
            if (SpeechEvent.EVENT_SESSION_ID == eventType) {
                String sid = obj.getString(SpeechEvent.KEY_EVENT_AUDIO_URL);
                Log.d(TAG, "session id =" + sid);
            }
        }
    };


    private WakeuperListener mWakeuperListener = new WakeuperListener() {

        @Override
        public void onResult(WakeuperResult result) {
            try {
                String text = result.getResultString();
                JSONObject object;
                object = new JSONObject(text);
                StringBuffer buffer = new StringBuffer();
                buffer.append("【RAW】 " + text);
                buffer.append("\n");
                buffer.append("【操作类型】" + object.optString("sst"));
                buffer.append("\n");
                buffer.append("【唤醒词id】" + object.optString("id"));
                buffer.append("\n");
                buffer.append("【得分】" + object.optString("score"));
                buffer.append("\n");
                buffer.append("【前端点】" + object.optString("bos"));
                buffer.append("\n");
                buffer.append("【尾端点】" + object.optString("eos"));
                resultString = buffer.toString();
                Log.e(TAG, resultString);
//                data.add(new MainItem(1, "您好，请说"));
//                adapter.notifyItemChanged(data.size() - 1);
                addWaitView("您好，请说");
                stopWake();
                stopTts();
                startLat();
            } catch (JSONException e) {
                resultString = "结果解析出错";
                e.printStackTrace();
            }
        }

        @Override
        public void onError(SpeechError error) {
//            showTip(error.getPlainDescription(true));
        }

        @Override
        public void onBeginOfSpeech() {
        }

        @Override
        public void onEvent(int eventType, int isLast, int arg2, Bundle obj) {
            switch (eventType) {
                // EVENT_RECORD_DATA 事件仅在 NOTIFY_RECORD_DATA 参数值为 真 时返回
                case SpeechEvent.EVENT_RECORD_DATA:
                    final byte[] audio = obj.getByteArray(SpeechEvent.KEY_EVENT_RECORD_DATA);
                    Log.i(TAG, "ivw audio length: " + audio.length);
                    break;
            }
        }

        @Override
        public void onVolumeChanged(int volume) {

        }
    };


    /**
     * 开始合成语音播放
     */
    private void startTts(String content) {
        // 清空参数
        mTts.setParameter(SpeechConstant.PARAMS, null);
        //设置合成
        if (mTtsEngineType.equals(SpeechConstant.TYPE_CLOUD)) {
            //设置使用云端引擎
            mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
            //设置发音人
            mTts.setParameter(SpeechConstant.VOICE_NAME, voicerCloud);

        }
        //设置合成语速
        mTts.setParameter(SpeechConstant.SPEED, mSharedPreferences.getString("speed_preference", "50"));
        //设置合成音调
        mTts.setParameter(SpeechConstant.PITCH, mSharedPreferences.getString("pitch_preference", "50"));
        //设置合成音量
        mTts.setParameter(SpeechConstant.VOLUME, mSharedPreferences.getString("volume_preference", "50"));
        //设置播放器音频流类型
        mTts.setParameter(SpeechConstant.STREAM_TYPE, mSharedPreferences.getString("stream_preference", "3"));
        //	mTts.setParameter(SpeechConstant.STREAM_TYPE, AudioManager.STREAM_MUSIC+"");

        // 设置播放合成音频打断音乐播放，默认为true
        mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true");

        // 设置音频保存路径，保存音频格式支持pcm、wav，设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
        mTts.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
        mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH,
                getExternalFilesDir("msc").getAbsolutePath() + "/tts.pcm");

        int code = mTts.startSpeaking(content, mTtsListener);
        if (code != ErrorCode.SUCCESS) {
            showTip("语音合成失败,错误码: " + code + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");
        }
    }

    /**
     * 结束合成语音播放
     */
    private void stopTts() {
        mTts.stopSpeaking();
    }

    /**
     * 暂停合成语音播放
     */
    private void pauseTts() {
        mTts.pauseSpeaking();
    }


    /**
     * 初始化监听。
     * <p>
     * 机器人这个项目 暂时用不到
     */
    private InitListener mTtsInitListener = new InitListener() {
        @Override
        public void onInit(int code) {
            Log.d(TAG, "InitListener init() code = " + code);
            if (code != ErrorCode.SUCCESS) {
                showTip("初始化失败,错误码：" + code + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");

            } else {
                // 初始化成功，之后可以调用startSpeaking方法
                // 注：有的开发者在onCreate方法中创建完合成对象之后马上就调用startSpeaking进行合成，
                // 正确的做法是将onCreate中的startSpeaking调用移至这里
            }
        }
    };


    /**
     * 合成回调监听。
     */
    private SynthesizerListener mTtsListener = new SynthesizerListener() {

        @Override
        public void onSpeakBegin() {
            //showTip("开始播放");
            Log.d(TAG3, "开始播放：" + System.currentTimeMillis());
        }

        @Override
        public void onSpeakPaused() {
            showTip("暂停播放");
        }

        @Override
        public void onSpeakResumed() {
            showTip("继续播放");
        }

        @Override
        public void onBufferProgress(int percent, int beginPos, int endPos,
                                     String info) {
            // 合成进度
//            mPercentForBuffering = percent;
//            showTip(String.format(getString(R.string.tts_toast_format),
//                    mPercentForBuffering, mPercentForPlaying));
        }

        @Override
        public void onSpeakProgress(int percent, int beginPos, int endPos) {
            // 播放进度
//            mPercentForPlaying = percent;
//            showTip(String.format(getString(R.string.tts_toast_format),
//                    mPercentForBuffering, mPercentForPlaying));
        }

        @Override
        public void onCompleted(SpeechError error) {
//            if (error == null) {
//                showTip("播放完成");
//            } else {
//                showTip(error.getPlainDescription(true));
//            }
        }

        @Override
        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
            // 以下代码用于获取与云端的会话id，当业务出错时将会话id提供给技术支持人员，可用于查询会话日志，定位出错原因
            // 若使用本地能力，会话id为null
            if (SpeechEvent.EVENT_SESSION_ID == eventType) {
                String sid = obj.getString(SpeechEvent.KEY_EVENT_AUDIO_URL);
                Log.d(TAG, "session id =" + sid);
            }

            //实时音频流输出参考
			/*if (SpeechEvent.EVENT_TTS_BUFFER == eventType) {
				byte[] buf = obj.getByteArray(SpeechEvent.KEY_EVENT_TTS_BUFFER);
				Log.e("MscSpeechLog", "buf is =" + buf);
			}*/
        }
    };


    /**
     * 添加用户提问词
     */
    private void addUserText(String content) {
        View view = LayoutInflater.from(this).inflate(R.layout.main_tv_user, llContent, false);
        TextView tv = view.findViewById(R.id.tv);
        tv.setText(content);
        llContent.addView(view);
    }

    /**
     * 添加请等待 + 添加您好请说
     */
    private void addWaitView(String content) {
        View view = LayoutInflater.from(this).inflate(R.layout.main_tv_wait, llContent, false);
        TextView tv = view.findViewById(R.id.tv);
        tv.setText(content);
        llContent.addView(view);
    }

    /**
     * 添加机器回答词
     */
    private void addKitText(String content) {
        View view = LayoutInflater.from(this).inflate(R.layout.main_tv_kit, llContent, false);
        TypeWriterTextView tv = view.findViewById(R.id.typeTv);
        tv.setWriteStatusListener(new WriteStatusListener() {
            @Override
            public void onWriteFinish(@NonNull TypeWriterTextView view) {

            }

            @Override
            public void onWriteStart(@NonNull TypeWriterTextView view) {
                startTts(view.getText());
            }
        });
        tv.setText(content, true);
        llContent.addView(view);
    }


    private String getResource() {
        final String resPath = ResourceUtil.generateResourcePath(this, ResourceUtil.RESOURCE_TYPE.assets, "ivw/" + getString(R.string.app_id) + ".jet");
        Log.d(TAG, "resPath: " + resPath);
        return resPath;
    }

    private void showTip(final String str) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (mToast != null) {
                    mToast.cancel();
                }
                mToast = Toast.makeText(getApplicationContext(), str, Toast.LENGTH_SHORT);
                mToast.show();
            }
        });
    }


    /**
     * 初始化监听器。
     */
    private InitListener mInitListener = new InitListener() {

        @Override
        public void onInit(int code) {
            Log.d(TAG, "SpeechRecognizer init() code = " + code);
            if (code != ErrorCode.SUCCESS) {
                showTip("初始化失败，错误码：" + code + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");
            }
        }
    };

    /**
     * 获取权限
     */
    private ActivityResultLauncher<String> mPermissionResult = registerForActivityResult(new ActivityResultContracts.RequestPermission(), result -> {
        if (result) {
            /**
             * 开启唤醒监听
             */
            startWake();
        }
    });
}
